Conversation
4f82f37 to
bcf9a32
Compare
|
Interesting: the careful tests fail in exactly the same way as the tests fail on the opaque pyobject build. Maybe a useful hint that there's some unsafety happening somewhere... |
It looks like all the tests on Python 3.12 and newer fail the As @davidhewitt pointed out when I chatted with him last Friday - it's worth checking to see if doing that introduces performance regressions. If it does, we need to make sure we set things up so a codspeed uses the free-threaded build so it's not testing this configuration at all. I need to run benchmarks locally to see what the performance impact is. We also need a benchmark for creating PyClass instances - there is a benchmark for type initialization but not for instance initialization as far as I can see. |
|
I opened #5816 with a benchmark for creating an instance of a PyClass. I also had to hack in abi3 support for the benchmark crate, see #5818. Running the I ran the benchmarks on my personal development machine so there's some noise in the results. I'm showing the best of four runs of this benchmark for each commit. I see similar results on 3.15a6. Very roughly, there's a 5% performance cost. That's on the bubble for being significant but probably is too steep to force extensions to pay that cost on the 3.12 stable ABI. I think I'll go ahead and adjust this PR to only use |
|
I have a new theory about why subclassing is broken. The docs for
But right now Lines 497 to 502 in 46c16e4 I tried to get adjust the Maybe @Icxolu sorry to give you another ping but hopefully this more focused question is a little easier to answer. |
|
Yes, the #[pyclass(extends = PyDict]
struct Sub {
// sub fields
}
#[pyclass(extends = Sub]
struct SubSub{
// subsub fields
}I think the basic size of |
I guess it depends on what "additionally" means exactly there. I don't see any tests in CPython for setting a negative basicsize on a subtype of another heap type but at least this test only includes the size of the struct and not any supertypes. Maybe something else is broken? For whatever reason on this branch on the Python 3.12 limited API, if you try to access data stored on a superclass, you instead access data stored in the subclass. I'd love some help understanding what's broken. |
|
Maybe the issue is that |
|
More specifically, isn't this use of Lines 620 to 622 in 46c16e4 |
|
To me, it looks like this method on the variable class objects is probably broken in the face of subclassing: Lines 481 to 486 in fe00ce7 The call to With the below patch I get a failing test on main: (and if the fields are not both diff --git a/tests/test_inheritance.rs b/tests/test_inheritance.rs
index a7b0734602..4843c67fd9 100644
--- a/tests/test_inheritance.rs
+++ b/tests/test_inheritance.rs
@@ -304,7 +304,7 @@ mod inheriting_native_type {
#[test]
#[cfg(Py_3_12)]
fn inherit_list() {
- #[pyclass(extends=pyo3::types::PyList)]
+ #[pyclass(extends=pyo3::types::PyList, subclass)]
struct ListWithName {
#[pyo3(get)]
name: &'static str,
@@ -318,12 +318,38 @@ mod inheriting_native_type {
}
}
+ #[pyclass(extends=ListWithName)]
+ struct SubListWithName {
+ #[pyo3(get)]
+ sub_name: &'static str,
+ }
+
+ #[pymethods]
+ impl SubListWithName {
+ #[new]
+ fn new() -> PyClassInitializer<Self> {
+ PyClassInitializer::from(ListWithName::new()).add_subclass(Self {
+ sub_name: "Sublist",
+ })
+ }
+ }
+
Python::attach(|py| {
- let list_sub = pyo3::Bound::new(py, ListWithName::new()).unwrap();
+ let list_with_name = pyo3::Bound::new(py, ListWithName::new()).unwrap();
+ let sub_list_with_name = pyo3::Bound::new(py, SubListWithName::new()).unwrap();
py_run!(
py,
- list_sub,
- r#"list_sub.append(1); assert list_sub[0] == 1; assert list_sub.name == "Hello :)""#
+ list_with_name sub_list_with_name,
+ r#"
+ list_with_name.append(1)
+ assert list_with_name[0] == 1
+ assert list_with_name.name == "Hello :)", list_with_name.name
+
+ sub_list_with_name.append(1)
+ assert sub_list_with_name[0] == 1
+ assert sub_list_with_name.name == "Hello :)", sub_list_with_name.name
+ assert sub_list_with_name.sub_name == "Sublist", sub_list_with_name.sub_name
+ "#
);
});
}... will look into possible fixes for this urgently and seek to release 0.28.2 (probably yanking 0.28.0 and 0.28.1). |
6668d6e to
1970421
Compare
Towards fixing #5786.
This is done on top of #5753 because that PR is needed to make this work.
With some help from @davidhewitt, this almost works but subclassing seems to be broken.
I suspect using
Layoutto fill inLayoutAsBaseis incorrect here:pyo3/pyo3-macros-backend/src/pyclass.rs
Line 2833 in 5e317f0
But I'm not sure how to update the macros and the macro wrappers to get that to work correctly.
@Icxolu do you happen to have any insight about what's going wrong?
TODO:
PyModuldeDefin the FFI bindings.